<?php

declare(strict_types=1);

namespace App\Utils;

use App\Inc\OrderInc;

class Tool
{
    //PHP stdClass Object转array
    public static function objectToArray($array)
    {
        if (is_object($array)) {
            $array = (array)$array;
        }
        if (is_array($array)) {
            foreach ($array as $key => $value) {
                $array[$key] = self::objectToArray($value);
            }
        }

        return $array;
    }

    /**
     * 数组转对象
     *
     * @param $arr array|object
     *
     * @return object|null
     */
    public static function arrayToObject($arr)
    {
        if (is_array($arr)) {
            return json_decode(json_encode($arr));
        }
        if (is_object($arr)) {
            return $arr;
        }
    }

    /**
     * 坐标系转换 - 腾讯转百度
     * 中国正常GCJ02坐标-->百度地图BD09坐标
     * 腾讯地图用的也是GCJ02坐标
     *
     * @param float $lng 经度
     * @param float $lat 纬度
     *
     * @return array();
     */
    public static function tengxunToBaidu($lng, $lat)
    {
        $x_pi = 3.14159265358979324 * 3000.0 / 180.0;
        $x = $lng;
        $y = $lat;
        $z = sqrt($x * $x + $y * $y) + 0.00002 * sin($y * $x_pi);
        $theta = atan2($y, $x) + 0.000003 * cos($x * $x_pi);
        $lng = $z * cos($theta) + 0.0065;
        $lat = $z * sin($theta) + 0.006;

        return ['lat' => $lat, 'lng' => $lng];
    }

    /**
     * BD-09(百度)坐标转换成GCJ-02(火星，高德，腾讯)坐标
     *
     * @param bd_lon 百度经度
     * @param bd_lat 百度纬度
     * @param mixed $bd_lon
     * @param mixed $bd_lat
     *
     * @return array();
     */
    public static function baiduToGd($bd_lon, $bd_lat)
    {
        $x_pi = 3.14159265358979324 * 3000.0 / 180.0;
        $x = $bd_lon - 0.0065;
        $y = $bd_lat - 0.006;
        $z = sqrt($x * $x + $y * $y) - 0.00002 * sin($y * $x_pi);
        $theta = atan2($y, $x) - 0.000003 * cos($x * $x_pi);
        // $data['gg_lon'] = $z * cos($theta);
        // $data['gg_lat'] = $z * sin($theta);
        $gg_lon = $z * cos($theta);
        $gg_lat = $z * sin($theta);
        // 保留小数点后六位
        $data['gg_lon'] = round($gg_lon, 6);
        $data['gg_lat'] = round($gg_lat, 6);

        return $data;
    }

    public static function convertHump(array $data)
    {
        $result = [];
        foreach ($data as $key => $item) {
            if (is_array($item) || is_object($item)) {
                $result[self::convertUnderline($key)] = self::convertHump((array)$item);
            } else {
                $result[self::convertUnderline($key)] = $item;
            }
        }

        return $result;
    }

    /*
    *  weekday转换
    */
    public static function weekdaysBin2Dec(int $binCode)
    {
        $weekDays = [];
        for ($i = 1; $i <= 7; $i++) {
            if ($binCode && $binCode & pow(2, $i)) {
                $weekDays[] = $i;
            }
        }

        return $weekDays;
    }

    /*
    *  weekday转换
    */
    public static function weekdaysDec2Bin(array $weekDays)
    {
        $binCode = 0;
        for ($i = 1; $i <= 7; $i++) {
            $binCode += in_array($i, $weekDays) ? pow(2, $i) : 0;
        }

        return $binCode;
    }

    /**
     * @param $startHour
     * @param $interval
     *
     * @return int
     */
    public static function makePeriodCode(float $startHour, float $interval)
    {
        $periodCode = '';
        /*$periodCode .= $startHour < 10 ? '0' : '';*/
        if (ceil($startHour) == floor($startHour)) {
            $startHour = intval($startHour);
            $periodCode .= $startHour . '00';
        } else {
            $periodCode .= floor($startHour) . '30';
        }
        $endHour = $startHour + $interval;
        $periodCode .= $endHour < 10 ? '0' : '';
        if (ceil($endHour) == floor($endHour)) {
            $endHour = intval($endHour);
            $periodCode .= $endHour . '00';
        } else {
            $periodCode .= floor($endHour) . '30';
        }

        return (int)$periodCode;
    }

    public static function periodCode2Str($periodCode)
    {
        if ($periodCode > 12) {
            [$startHour, $startMinute, $endHour, $endMinute] = self::periodAnalyse($periodCode);
            $str = '';
            $str .= intval($startHour) . '点';
            if ($startMinute == '30') {
                $str .= '半';
            }
            $str .= '-';
            $str .= intval($endHour) . '点';
            if ($endMinute == '30') {
                $str .= '半';
            }

            return $str;
        } else {
            return OrderInc::TIMEPERIOD_MAP[$periodCode] ?? '';
        }
    }

    public static function periodCode2StrNew(string $periodCode, $onlyStart = false)
    {
        if ($periodCode > 12) {
            [$startHour, $startMinute, $endHour, $endMinute] = self::periodAnalyse($periodCode);

            if ($startHour < 10) {
                $startHour = '0' . $startHour;
            }
            if ($endHour < 10) {
                $endHour = '0' . $endHour;
            }

            $str = '';

            if ($startMinute == '30') {
                $str .= $startHour . ':30';
            } else {
                $str .= $startHour . ':00';
            }

            if ($onlyStart) {
                return $str;
            }

            $str .= '-';

            if ($endMinute == '30') {
                $str .= $endHour . ':30';
            } else {
                $str .= $endHour . ':00';
            }

            return $str;
        } else {
            $str = OrderInc::TIMEPERIOD_NEW_MAP[$periodCode] ?? '';
            if ($onlyStart) {
                $str = substr($str, 0, 5);
            }

            return $str;
        }
    }

    public static function periodAnalyse($periodCode)
    {
        $startCode = substr($periodCode, 0, -4) ?: '0000';
        $endCode = substr($periodCode, -4) ?: '0000';
        $startHour = substr($startCode, 0, -2) ?: '00';
        $startMinute = substr($startCode, -2) ?: '00';
        $endHour = substr($endCode, 0, -2) ?: '00';
        $endMinute = substr($endCode, -2) ?: '00';

        return [intval($startHour), $startMinute, intval($endHour), $endMinute];
    }

    public static function validateLongPeriodCode($code)
    {
        if (strlen($code) == 8) {
            $sCode = substr($code, 0, 4);
            $eCode = substr($code, 4, 4);
            $sHour = substr($sCode, 0, 2);
            $sMin = substr($sCode, 2, 2);
            $eHour = substr($eCode, 0, 2);
            $eMin = substr($eCode, 2, 2);
            if ($sCode < $eCode && $sHour >= 10 && $sHour <= 23 && in_array($sMin, [0, 30]) && $eHour >= 0 && $eHour <= 23 && in_array($eMin, [0, 30])) {
                return true;
            }

            return false;
        } elseif (strlen($code) == 7) {
            $sCode = substr($code, 0, 3);
            $eCode = substr($code, 3, 4);
            $sHour = substr($sCode, 0, 1);
            $sMin = substr($sCode, 2, 2);
            $eHour = substr($eCode, 0, 2);
            $eMin = substr($eCode, 2, 2);
            if ($sCode < $eCode && $sHour >= 1 && $sHour <= 9 && in_array($sMin, [0, 30]) && $eHour >= 0 && $eHour <= 23 && in_array($eMin, [0, 30])) {
                return true;
            }

            return false;
        } elseif (strlen($code) == 6) {
            $sCode = substr($code, 0, 2);
            $eCode = substr($code, 2, 4);
            $sMin = $sCode;
            $eHour = substr($eCode, 0, 2);
            $eMin = substr($eCode, 2, 2);
            if ($sCode < $eCode && in_array($sMin, [0, 30]) && $eHour >= 0 && $eHour <= 23 && in_array($eMin, [0, 30])) {
                return true;
            }

            return false;
        } elseif (strlen($code) == 4) {
            $eCode = $code;
            $eHour = substr($eCode, 0, 2);
            $eMin = substr($eCode, 2, 2);
            if ($eHour >= 0 && $eHour <= 23 && in_array($eMin, [0, 30])) {
                return true;
            }

            return false;
        } elseif (strlen($code) == 3) {
            $eCode = $code;
            $eHour = substr($eCode, 0, 1);
            $eMin = substr($eCode, 1, 2);
            if ($eHour >= 1 && $eHour <= 9 && in_array($eMin, [0, 30])) {
                return true;
            }

            return false;
        } elseif (strlen($code) == 2) {
            if ($code == 30) {
                return true;
            }

            return false;
        }

        return false;
    }

    /*
     * 下划线转驼峰
     */
    private static function convertUnderline($str)
    {
        return preg_replace_callback('/([-_]+([a-z]{1}))/i', function ($matches) {
            return strtoupper($matches[2]);
        }, $str);
    }
}
